﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SGP;
using System.Xml.Linq;
using System.Windows;

namespace WorldEditor
{
    public partial class Form1 : Form
    {
        bool looping;
        public bool Looping
        {
            get { return looping; }
            set { looping = value; }
        }

        // Width of Waypoint Squares
        public new int Width = 10;
        // Opacity of Images
        public new int Opacity = 255;

        // DirectX Wrappers
        ManagedDirect3D DX;
        ManagedTextureManager TM;

        // Path chosen at beginning of Application
        public string DefaultPath;

        Level CurLevel;
        Waypoint selected;

        public Form1()
        {
            InitializeComponent();
            looping = true;

            DX = ManagedDirect3D.Instance;
            TM = ManagedTextureManager.Instance;

            // Default for Scroll bars
            hScrollBar1.Visible = false;
            hScrollBar1.Enabled = false;

            vScrollBar1.Visible = false;
            vScrollBar1.Enabled = false;

            NewLevel();

            // Fill out info on screen
            FieldHeightNumUpDown.Value = CurLevel.Field.FieldHeight;
            BgHeightNumUpDown.Value = CurLevel.Field.BgHeight;
            MapWidthNumUpDown.Value = CurLevel.Field.ScreenWidth;
            MapHeightNumUpDown.Value = CurLevel.Field.ScreenHeight;

            // Initialize both
            DX.InitManagedDirect3D(WorldViewer, CurLevel.Field.ScreenWidth, CurLevel.Field.ScreenHeight, false);
            TM.InitManagedTextureManager(DX.Device, DX.Sprite);

            selected = new Waypoint();
            selected.PosX = -1;
            selected.PosY = -1;
        }

        private void ChooseFolder()
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();

            if (DialogResult.OK == dlg.ShowDialog())
                // Get Texture
                DefaultPath = dlg.SelectedPath;

            //this.TopMost = true;
        }

        private void NewLevel()
        {
            LevelsListBox.Items.Add(new Level(LevelsListBox.Items.Count));
            LevelsListBox.SelectedIndex = LevelsListBox.Items.Count - 1;
        }

        public new void Update()
        {
            // Update Image Data to Control Values
            CurLevel.Field.FieldHeight = (int)FieldHeightNumUpDown.Value;
            CurLevel.Field.BgHeight = (int)BgHeightNumUpDown.Value;
            CurLevel.Field.ScreenWidth = (int)MapWidthNumUpDown.Value;
            CurLevel.Field.ScreenHeight = (int)MapHeightNumUpDown.Value;

            // Update Field boundaries for Waypoints
            XPosNumUpDown.Maximum = CurLevel.Field.ScreenWidth;
            YPosNumUpDown.Minimum = CurLevel.Field.ScreenHeight - CurLevel.Field.FieldHeight;
            YPosNumUpDown.Maximum = CurLevel.Field.ScreenHeight;

            // Check scroll bars
            if (WorldViewer.Size.Width < CurLevel.Field.ScreenWidth)
            {
                hScrollBar1.Visible = true;
                hScrollBar1.Enabled = true;
                hScrollBar1.Maximum = (CurLevel.Field.ScreenWidth - WorldViewer.Size.Width);
            }
            else
            {
                hScrollBar1.Visible = false;
                hScrollBar1.Enabled = false;
                hScrollBar1.Value = 0;
            }

            if (WorldViewer.Size.Height < CurLevel.Field.ScreenHeight)
            {
                vScrollBar1.Visible = true;
                vScrollBar1.Enabled = true;
                vScrollBar1.Maximum = (CurLevel.Field.ScreenHeight - WorldViewer.Size.Height);
            }
            else
            {
                vScrollBar1.Visible = false;
                vScrollBar1.Enabled = false;
                vScrollBar1.Value = 0;
            }

            //Tab Selection
            if (EditorTabControl.SelectedTab == ImagesTab)
                Opacity = 255;
            else
                Opacity = 128;

            if (selected != null)
            {
                UpdateButton.Enabled = true;
                RemoveButton.Enabled = true;
            }
            else
            {
                UpdateButton.Enabled = false;
                RemoveButton.Enabled = false;
            }
        }

        public void Render()
        {
            DX.DeviceBegin();
            DX.Clear(WorldViewer, WorldViewer.BackColor);
            DX.SpriteBegin();

            if (CurLevel.FieldImg != -1)
                TM.Draw(CurLevel.FieldImg, 0 - hScrollBar1.Value, CurLevel.Field.ScreenHeight - CurLevel.Field.FieldHeight - vScrollBar1.Value, 1.0f, 1.0f, new Rectangle(0, 0, CurLevel.Field.ScreenWidth, CurLevel.Field.FieldHeight),
                    CurLevel.Field.ScreenWidth / 2, CurLevel.Field.FieldHeight / 2, 0.0f, Color.FromArgb(Opacity, Color.White));

            if (CurLevel.BgImg != -1)
                TM.Draw(CurLevel.BgImg, 0 - hScrollBar1.Value, 0 - vScrollBar1.Value, 1.0f, 1.0f, new Rectangle(0, 0, CurLevel.Field.ScreenWidth, CurLevel.Field.BgHeight),
                    CurLevel.Field.ScreenWidth / 2, CurLevel.Field.BgHeight / 2, 0.0f, Color.FromArgb(Opacity, Color.White));

            DX.Sprite.Flush();

            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < CurLevel.Paths[i].Waypoints.Count; ++j)
                {
                    Waypoint wp = CurLevel.Paths[i].Waypoints[j];
                    Rectangle rect = new Rectangle(wp.PosX - Width - hScrollBar1.Value, wp.PosY - Width - vScrollBar1.Value, Width * 2, Width * 2);
                    Color color = Color.Black;
                    switch (i)
                    {
                        case 0:
                            color = Color.Red;
                            break;
                        case 1:
                            color = Color.Green;
                            break;
                        case 2:
                            color = Color.Blue;
                            break;
                    }

                    DX.DrawRect(rect, color);

                    if (selected == wp)
                        DX.DrawEmptyRect(rect, Color.Yellow);

                    // Draw lines between waypoints
                    if (j > 0)
                    {
                        Waypoint wp2 = CurLevel.Paths[i].Waypoints[j - 1];
                        DX.DrawLine(wp.PosX - hScrollBar1.Value, wp.PosY - vScrollBar1.Value,
                            wp2.PosX - hScrollBar1.Value, wp2.PosY - vScrollBar1.Value, color, 2);
                    }
                }
            }

            DX.DrawEmptyRect(new Rectangle(0 - hScrollBar1.Value, 0 - vScrollBar1.Value, CurLevel.Field.ScreenWidth, CurLevel.Field.ScreenHeight), Color.Gray);

            if (EditorTabControl.SelectedTab == GameTab)
                DX.DrawText("Right-Click to Select Waypoint", CurLevel.Field.ScreenWidth / 2 - 100 - hScrollBar1.Value, 5 - vScrollBar1.Value, Color.Yellow);

            DX.SpriteEnd();
            DX.DeviceEnd();

            DX.Present();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            looping = false;
            DX.Shutdown();
            TM.ShutdownManagedTextureManager();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void FieldImg_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.InitialDirectory = DefaultPath;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                // Get Texture
                CurLevel.FieldImg = TM.LoadTexture(dlg.FileName, 0);

                CurLevel.Field.FieldPath = dlg.SafeFileName;

                FieldFileTextBox.Text = dlg.SafeFileName;
            }
        }

        private void BgImageButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.InitialDirectory = DefaultPath;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                // Get Texture
                CurLevel.BgImg = TM.LoadTexture(dlg.FileName, 0);

                CurLevel.Field.BgPath = dlg.SafeFileName;

                BgFileTextBox.Text = dlg.SafeFileName;
            }
        }

        private void PathsListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            PathIDComboBox.SelectedIndex = PathsListBox.SelectedIndex;
            ChangeWaypointList(PathsListBox.SelectedIndex);
        }

        private void PathIDComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            PathsListBox.SelectedIndex = PathIDComboBox.SelectedIndex;
            ChangeWaypointList(PathIDComboBox.SelectedIndex);
        }

        private void ChangeWaypointList(int index)
        {
            WaypointsListBox.Items.Clear();
            WptIDComboBox.Items.Clear();
            for (int i = 0; i < CurLevel.Paths[index].Waypoints.Count; ++i)
            {
                WaypointsListBox.Items.Add(CurLevel.Paths[index].Waypoints[i]);
                WptIDComboBox.Items.Add(i);
            }

            XPosNumUpDown.Value = XPosNumUpDown.Minimum;
            YPosNumUpDown.Value = YPosNumUpDown.Minimum;
        }

        private void AddButton_Click(object sender, EventArgs e)
        {
            int index = PathIDComboBox.SelectedIndex;
            if (index >= 0)
            {
                Waypoint waypoint = new Waypoint();
                waypoint.Index = CurLevel.Paths[index].Waypoints.Count + 1;
                waypoint.PathID = index;
                waypoint.PosX = (int)XPosNumUpDown.Value;
                waypoint.PosY = (int)YPosNumUpDown.Value;

                CurLevel.Paths[index].Waypoints.Add(waypoint);

                ChangeWaypointList(index);
            }
        }

        private void WaypointsListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (WaypointsListBox.SelectedIndex >= 0)
            {
                Waypoint waypoint = CurLevel.Paths[PathsListBox.SelectedIndex].Waypoints[WaypointsListBox.SelectedIndex];
                XPosNumUpDown.Value = (decimal)waypoint.PosX;
                YPosNumUpDown.Value = (decimal)waypoint.PosY;
                selected = waypoint;
                WptIDComboBox.SelectedIndex = selected.Index;
            }
            else
                selected = null;
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();

            dlg.Filter = "All Files|*.*|Xml Files|*.xml";
            dlg.FilterIndex = 2;
            dlg.DefaultExt = "xml";
            dlg.FileName = "WorldXML";

            if (DialogResult.OK == dlg.ShowDialog())
            {
                // Root Element Levels
                XElement xRoot = new XElement("Levels");

                for (int h = 0; h < LevelsListBox.Items.Count; ++h)
                {
                    CurLevel = (Level)LevelsListBox.Items[h];

                    XElement xLevel = new XElement("Level");
                    xRoot.Add(xLevel);

                    // All attributes of a level
                    XAttribute xFImg = new XAttribute("FieldImage", CurLevel.Field.FieldPath);
                    xLevel.Add(xFImg);

                    XAttribute xBgImg = new XAttribute("BgImage", CurLevel.Field.BgPath);
                    xLevel.Add(xBgImg);

                    XAttribute xWidth = new XAttribute("Width", CurLevel.Field.ScreenWidth);
                    xLevel.Add(xWidth);

                    XAttribute xHeight = new XAttribute("Height", CurLevel.Field.ScreenHeight);
                    xLevel.Add(xHeight);

                    XAttribute xBgHeight = new XAttribute("BgHeight", CurLevel.Field.BgHeight);
                    xLevel.Add(xBgHeight);

                    XAttribute xFieldHeight = new XAttribute("FieldHeight", CurLevel.Field.FieldHeight);
                    xLevel.Add(xFieldHeight);

                    // Add Paths to level
                    for (int i = 0; i < 3; ++i)
                    {
                        XElement xPath = new XElement("Path");
                        xLevel.Add(xPath);

                        // Path Attributes
                        XAttribute xNum = new XAttribute("Num", CurLevel.Paths[i].PathID);
                        xPath.Add(xNum);

                        // Add Waypoints to Path
                        for (int j = 0; j < CurLevel.Paths[i].Waypoints.Count; ++j)
                        {
                            XElement xWaypoint = new XElement("Waypoint");
                            xPath.Add(xWaypoint);

                            // Add Attributes to Waypoint
                            XAttribute xPosX = new XAttribute("PosX", CurLevel.Paths[i].Waypoints[j].PosX);
                            xWaypoint.Add(xPosX);

                            XAttribute xPosY = new XAttribute("PosY", CurLevel.Paths[i].Waypoints[j].PosY);
                            xWaypoint.Add(xPosY);
                        }
                    }
                }

                xRoot.Save(dlg.FileName);
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All Files|*.*|Xml Files|*.xml";
            dlg.FilterIndex = 2;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                XElement xRoot = XElement.Load(dlg.FileName);

                // Get Elements of Root
                IEnumerable<XElement> xLevels = xRoot.Elements();

                LevelsListBox.Items.Clear();

                int h = 0;
                // loop through each level
                foreach (XElement xLevel in xLevels)
                {
                    Level level = new Level(h);
                    ++h;

                    // Get Attributes of each level
                    XAttribute xFImg = xLevel.Attribute("FieldImage");
                    level.Field.FieldPath = Convert.ToString(xFImg.Value);

                    XAttribute xBgImg = xLevel.Attribute("BgImage");
                    level.Field.BgPath = Convert.ToString(xBgImg.Value);

                    XAttribute xWidth = xLevel.Attribute("Width");
                    level.Field.ScreenWidth = Convert.ToInt32(xWidth.Value);

                    XAttribute xHeight = xLevel.Attribute("Height");
                    level.Field.ScreenHeight = Convert.ToInt32(xHeight.Value);

                    XAttribute xBgHeight = xLevel.Attribute("BgHeight");
                    level.Field.BgHeight = Convert.ToInt32(xBgHeight.Value);

                    XAttribute xFHeight = xLevel.Attribute("FieldHeight");
                    level.Field.FieldHeight = Convert.ToInt32(xFHeight.Value);

                    // Get Paths of the level
                    IEnumerable<XElement> xPaths = xLevel.Elements();
                    // Loop through each path
                    foreach (XElement xPath in xPaths)
                    {
                        // Get Path Attributes
                        XAttribute xNum = xPath.Attribute("Num");
                        int num = Convert.ToInt32(xNum.Value);

                        // Create new path
                        //level.Paths[num - 1].Waypoints.Clear();
                        level.Paths[num - 1] = new Path(num);

                        // Get Waypoints of Path
                        IEnumerable<XElement> xWaypoints = xPath.Elements();
                        // Loop through elements
                        int i = 0;
                        foreach (XElement xWpt in xWaypoints)
                        {
                            // Create waypoint
                            Waypoint wpt = new Waypoint();

                            // Get attributes of waypoint
                            XAttribute xPosX = xWpt.Attribute("PosX");
                            XAttribute xPosY = xWpt.Attribute("PosY");

                            // assign values to waypoint
                            wpt.Index = i;
                            wpt.PathID = num - 1;
                            wpt.PosX = Convert.ToInt32(xPosX.Value);
                            wpt.PosY = Convert.ToInt32(xPosY.Value);

                            // add to paths list
                            level.Paths[num - 1].Waypoints.Add(wpt);

                            ++i;
                        }
                    }
                    LevelsListBox.Items.Add(level);
                }

                LevelsListBox.SelectedIndex = 0;
            }
        }

        private void WorldViewer_MouseClick(object sender, MouseEventArgs e)
        {
            if (EditorTabControl.SelectedTab == GameTab)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    if (e.Y + vScrollBar1.Value > CurLevel.Field.ScreenHeight - CurLevel.Field.FieldHeight &&
                        e.X + hScrollBar1.Value < CurLevel.Field.ScreenWidth)
                    {
                        Waypoint wpt = new Waypoint();
                        int index = PathIDComboBox.SelectedIndex;
                        wpt.PathID = CurLevel.Paths[index].PathID;
                        wpt.Index = CurLevel.Paths[index].Waypoints.Count;
                        wpt.PosX = e.X + hScrollBar1.Value;
                        wpt.PosY = e.Y + vScrollBar1.Value;

                        CurLevel.Paths[index].Waypoints.Add(wpt);
                        ChangeWaypointList(index);
                    }
                }
                else if (e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    for (int i = 0; i < 3; ++i) // loop through paths
                    {
                        for (int j = 0; j < CurLevel.Paths[i].Waypoints.Count; ++j) // loop through waypoints
                        {
                            Waypoint wp = CurLevel.Paths[i].Waypoints[j];
                            Rectangle rect = new Rectangle(wp.PosX - Width - hScrollBar1.Value, wp.PosY - Width - vScrollBar1.Value, Width * 2, Width * 2);

                            if (rect.Contains(e.Location)) // mouse over waypoint
                            {
                                PathsListBox.SelectedIndex = i;
                                WaypointsListBox.SelectedIndex = j;
                            }
                        }
                    }
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ChooseFolder();
        }

        private void AddLevelButton_Click(object sender, EventArgs e)
        {
            NewLevel();
        }

        private void LevelsListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            CurLevel = (Level)LevelsListBox.Items[LevelsListBox.SelectedIndex];

            BgFileTextBox.Text = CurLevel.Field.BgPath;
            FieldFileTextBox.Text = CurLevel.Field.FieldPath;
            MapHeightNumUpDown.Value = CurLevel.Field.ScreenHeight;
            MapWidthNumUpDown.Value = CurLevel.Field.ScreenWidth;
            FieldHeightNumUpDown.Value = CurLevel.Field.FieldHeight;
            BgHeightNumUpDown.Value = CurLevel.Field.BgHeight;

            if (CurLevel.Field.FieldPath.Length > 0)
                CurLevel.FieldImg = TM.LoadTexture(DefaultPath + "\\" + CurLevel.Field.FieldPath, 0);
            if (CurLevel.Field.BgPath.Length > 0)
                CurLevel.BgImg = TM.LoadTexture(DefaultPath + "\\" + CurLevel.Field.BgPath, 0);

            PathsListBox.Items.Clear();
            PathIDComboBox.Items.Clear();
            for (int i = 0; i < 3; ++i)
            {
                //Set Path IDs
                if (CurLevel.Paths[i] == null)
                    CurLevel.Paths[i] = new Path(i + 1);
                // Fill out Paths List Box
                PathsListBox.Items.Add(CurLevel.Paths[i]);
                // Fill out PathID box
                PathIDComboBox.Items.Add(i + 1);
            }
            PathIDComboBox.SelectedIndex = 0;
        }

        private void UpdateButton_Click(object sender, EventArgs e)
        {
            // Change path
            int index = PathIDComboBox.SelectedIndex;
            if (index != selected.PathID)
            {
                // Remove old waypoint in old path
                CurLevel.Paths[selected.PathID].Waypoints.RemoveAt(selected.Index);
                // Insert new waypoint in new path
                selected.PathID = index;
                CurLevel.Paths[selected.PathID].Waypoints.Insert(selected.Index, selected);
            }

            index = WptIDComboBox.SelectedIndex;
            if (index != selected.Index)
            {
                // Remove old waypoint
                CurLevel.Paths[selected.PathID].Waypoints.RemoveAt(selected.Index);
                // Insert new waypoint at new pos
                selected.Index = index;
                CurLevel.Paths[selected.PathID].Waypoints.Insert(selected.Index, selected);
            }

            selected.PosX = (int)XPosNumUpDown.Value;
            selected.PosY = (int)YPosNumUpDown.Value;
            ChangeWaypointList(selected.PathID);

            CurLevel.Paths[selected.PathID].Waypoints[selected.Index] = selected;

            selected = null;
        }

        private void RemoveButton_Click(object sender, EventArgs e)
        {

        }
    }
}
